﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using YAPACS.BusinessObjects.Managements.Workflows;
using YAPACS.Workflows;

namespace YAPACS.RisServer.Controllers;
[Authorize]
public class WorkflowController(
    IWorkflowInvoker invoker,
    IRepository<Workflow, Guid> workflowRepository,
    IRepository<WorkflowAccessControl, Guid> workflowAccessControlRepository,
    IAsyncQueryableExecuter queryableExecuter,
    IOptions<WorkflowOptions> workflowOptions,
    IServiceProvider serviceProvider) : AbpControllerBase
{
    private readonly IWorkflowInvoker _invoker = invoker;
    private readonly IRepository<Workflow, Guid> _workflowRepository = workflowRepository;
    private readonly IRepository<WorkflowAccessControl, Guid> _workflowAccessControlRepository = workflowAccessControlRepository;
    private readonly IAsyncQueryableExecuter _queryableExecuter = queryableExecuter;
    private readonly WorkflowOptions _workflowOptions = workflowOptions.Value;
    private readonly IServiceProvider _serviceProvider = serviceProvider;

    [HttpPost]
    [Route("/api/workflow/invoke")]
    public async Task<IActionResult> InvokeAction([FromQuery] string actionId, [FromBody] Dictionary<string, object> data)
    {
        try
        {
            var input = new WorkflowInput() { { "Input", data } };

            if (_workflowOptions.WorkflowTypes.TryGetValue(actionId, out var workflowType))
            {
                if (_serviceProvider.GetService(workflowType) is IWorkflow workflow)
                {
                    return Ok(await workflow.InvokeAsync(input));
                }
            }

            var workflowOutput = await _invoker.InvokeAsync(actionId, input);
            return Ok(workflowOutput);
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await CurrentUnitOfWork.RollbackAsync();
            return Ok(new WorkflowOutput()
            {
                Success = false,
                Error = ex.Message
            });
        }
    }

    [HttpGet]
    [HttpPost]
    [Route("/api/workflow/{code}")]
    [AllowAnonymous]
    public async Task<IActionResult> Index(string code, string accessKey)
    {
        var workflowAccessControl = await _workflowAccessControlRepository.GetAsync(x => x.AccessKey == accessKey);
        var allowWorkflow = workflowAccessControl.AllowWorkflow?.ToUpperInvariant();
        if (!string.IsNullOrWhiteSpace(allowWorkflow) && workflowAccessControl.IsActive)
        {
            if (allowWorkflow == "*" || allowWorkflow.Split(',').Select(x => x.Trim()).Contains(code.ToUpperInvariant()))
            {
                try
                {
                    var workflowOutput = await _invoker.InvokeByCodeAsync(code, []);
                    if (workflowOutput != null)
                    {
                        return Ok(workflowOutput);
                    }
                    else
                    {
                        return NotFound();
                    }
                }
                catch (Exception ex)
                {
                    return Ok(new WorkflowOutput()
                    {
                        Success = false,
                        Error = ex.Message
                    });
                }
            }
        }
        return Forbid();
    }
}
